////////////////////////////////////////////////////////////////////////////////
// File:        License.cpp
// Purpose:     Implements License class for encoding, decoding and management of
//              username and password.
// Author:      Tukero
// Modified by: 
// Copyright:   (c) Tukero <tukero@gmail.com>
// Licence:     GNU/LGPL v3 (included all algorithms)
////////////////////////////////////////////////////////////////////////////////

#include "License.h"

WX_DEFINE_LIST(LinkListLicense);

License::License()
{ 
    m_Username.Empty(); 
    m_Password.Empty(); 
    m_ExpirationDate = 0;
    m_IsValid = false;
    m_ExpirationState = 0;
}

License::License(License *license)
{ 
    m_Username = license->GetUsername();
    m_Password = license->GetPassword();
    m_ExpirationDate = license->GetExpirationDate();
    m_IsValid = license->IsValid();
    m_ExpirationState = license->GetExpirationState();
}

License::License(const wxString user, const wxString pass, bool isValid, int expirationState) 
{ 
    m_Username=user;
    m_Password=pass;
    m_ExpirationDate = 0;
    m_IsValid = isValid;
    m_ExpirationState = expirationState;
}

bool License::IsValid() { return m_IsValid; }
void License::SetValid(bool validity) { m_IsValid = validity; }

void License::SetExpirationState(int state) { m_ExpirationState = state; }
int License::GetExpirationState() { return m_ExpirationState; }

void License::SetUsername(wxString user) { m_Username=user; }
wxString License::GetUsername() { return m_Username; }
    
void License::SetPassword(wxString pass) { m_Password=pass; }
wxString License::GetPassword() { return m_Password; }

void License::SetExpirationDate(unsigned long ms) { m_ExpirationDate = ms; }
unsigned long License::GetExpirationDate() { return m_ExpirationDate; } 

bool License::IsSameAs(const License &anotherLicense)
{
    return (anotherLicense.m_Username == m_Username && anotherLicense.m_Password == m_Password);
}
wxChar License::GetPassCharW(int position)
{
    wxChar decoXor = 0;

    static const unsigned short passSizes[6]={31,29,23,17,13,11};

    //KEY constants used to encode or decode any text with any length
    static const unsigned short nodPass[31+29+23+17+13+11]={
        0x41,0xec,0x9b,0x52,0x1f,0x57,0x81,0xe1,0xae,0xb3,0x36,0x23,0x6f,0x50,0xbb,0x74,0x0f,0xc0,0x3a,0xe2,0xc7,0xea,0x46,0xbe,0xe3,0x71,0x45,0xbf,0x9e,0xde,0x07,
        0x08,0x13,0x10,0xd1,0x05,0xeb,0x6a,0x8f,0xce,0x66,0xc5,0x59,0x82,0xb0,0x99,0x61,0x41,0xb3,0x1a,0x0d,0x82,0x47,0xad,0x56,0x8c,0x26,0xb5,0xa4,0xc8,
        0x54,0x7a,0x67,0x68,0xc1,0x50,0x14,0xcc,0xfa,0x17,0xdf,0x8c,0xb8,0xf5,0x7e,0x72,0xa7,0x02,0xf3,0x34,0x04,0x52,0xf1,
        0xf7,0x32,0x94,0x0f,0x0b,0xb0,0x1a,0x92,0x26,0x55,0x2c,0x4b,0xee,0x8a,0xe3,0x23,0x85,
        0xac,0x24,0x57,0x8f,0x6b,0xa3,0xc2,0xab,0xd6,0x54,0xef,0x37,0x49,
        0x27,0x45,0xfb,0x82,0x66,0x0f,0xdc,0x69,0x31,0xa7,0xda
    };
    int passPosition=0;
    wxChar ch;
    for (int i=0;i<6;i++)
    {
        ch = (nodPass[passPosition + (position*2 +1)%passSizes[i] ] << 8) | 
              nodPass[passPosition + (position*2   )%passSizes[i] ];
        decoXor ^= ch;
        passPosition += passSizes[i];
    }   
    return decoXor;
}

void License::workPass(FORMATS formatInput, FORMATS formatOutput, OPERATIONS operation, wxString* strInput = NULL, wxMemoryBuffer* binInput = NULL, wxString* strOutput = NULL, wxMemoryBuffer* binOutput = NULL)
{   
    //variables initialization
    switch(formatOutput)
    {
    case STRING:
        if (strOutput == NULL) return;

        strOutput->Empty();          //reset string variable

        if (operation == ENCODE)
            strOutput->Alloc(20);

        break;
    case BINARY:
        if (binOutput == NULL) return;

        binOutput->SetDataLen(0);    //reset memorybuffer variable

        if (operation == ENCODE)
        {
            if (formatInput == STRING && strInput != NULL)
                binOutput->SetBufSize(strInput->Len() * 2);
            else if (formatInput == BINARY && binInput != NULL)
                binOutput->SetBufSize(binInput->GetDataLen());
            else
                binOutput->SetBufSize(20);
        }
        break;
    }

    wxString strPass;

    //changing all input formats to wxString
    switch (formatInput)
    {
    case STRING:
        if (strInput == NULL) return;

        strPass = *strInput;
        break;
    case BINARY:
        if (binInput == NULL) return;

        wxString *toStr = new wxString((wxChar *)binInput->GetData(),binInput->GetDataLen()/sizeof(wxChar));
        strPass = *toStr;
        break;
    }

    
    if (operation == ENCODE)
    {
        wxString passWithZeros;
        passWithZeros.Alloc(strPass.Len()+2);

        int c=0;
        int len=strPass.Len();

        //appends zeros to each character
        static unsigned char zero = 0;
        for (c=0;c<len;c++)
        {
            passWithZeros.Append(strPass[c]);
            passWithZeros.Append(zero);
        }
        
        //The ESET encode algorithm ohhh right :) - tukero@gmail.com
        //---------------------
        //    ______  __  __  _____  __ __
        //   /  ___/ / / / / / ___/ / /' /
        //  /  __/  / /_/ / / /__  /   <   TO ALL RIPPERS!
        // /__/     \___.'  \___/ /_/\__\
        //---------------------
        // n          1    2    3    4    5  ...  n-2  n-1   n
        // table1   #a1  #a2  #a3  #a4  #a5  ...  #a1  #a2  ...
        //           |                                       |
        //          XOR                                     XOR
        //           |                                       |
        // table2   #b1  #b2  #b3  #b4  ...  #b1  #b2  #b3  ...
        //           |                                       |
        //          XOR                                     XOR
        //           |                                       |
        // table3   #c1  #c2  #c3  ...  #c1  #c2  #c3  #c4  ...
        //           |                                       |
        //          XOR                                     XOR
        //           |                                       |
        // tableN   ...                                     ...
        //           |                                       |
        //          XOR                                     XOR
        //           |                                       |
        // table6   #f1  #f2  #f3  ...  #f1  #f2  #f3  #f4  ...
        //           =                                       =
        //          k(1)             ...                    k(n)
        //
        // If we have:
        //    k(n) --> A password constant in n position (n is the N character that we have to encode)
        // Algorithm:
        //   The N encoded character = Xor( K(n), ascii N unicode decoded character )
        //   Example: 
        //            Word to encode: TK
        //            First, transform to unicode, then we have: T.K.    (where the dot (.) is for the ascii = 0, dot = character zero)
        //                                                       T = ascii 84      . = ascii 0      K = ascii 75      . = ascii 0
        //            The first encoded character  = Xor( K(1), 'T') = Xor( K(1), 84)  T
        //                second encoded character = Xor( K(2), 0 )  = Xor( K(2), 0)   .
        //                third encoded character  = Xor( K(3), 'K') = Xor( K(3), 75)  K
        //                last encoded character   = Xor( K(4), 0)   = Xor( K(4), 0)   .
        //            Where:
        //                K(1) = 0x41 xor 0x08 xor 0x54 xor 0xf7 xor ...  (see the tables and the diagram)
        //                K(2) = 0xec xor 0x13 xor 0x7a xor 0x32 xor...
        //                ...  = ...
        // Do you need more help? tukero@gmail.com  no rippers, thanks.
        // 

        len = strPass.Len();
        wxChar coded = 0;
        for (c=0;c<len;c++)
        {
            coded=strPass[c]^GetPassCharW(c);
            switch(formatOutput)
            {
            case STRING:
                strOutput->Append(coded);
                break;
            case BINARY:
                binOutput->AppendData((void *)&coded,sizeof(wxChar));
                break;
            }
        }
    }
    else if (operation == DECODE)
    {        
        // oh right, the hot part.
        // it is very simple, it's the inverse operation of encode function... let me see...
        // we have the encode function:
        //   The N encoded character = Xor( K(n), ascii N unicode decoded character )
        // We can find:
        //   - The N encoded character
        //   - K(n)     (using the tables)
        // See again:
        //   The N encoded character = Xor( K(n), ascii N unicode decoded character )
        //               KNOWN       = Xor(KNOWN, UNKNOWN)
        // The, we need find:
        //  - ascii N unicode DECODED character 
        // Simple Mathematics! If we have   A xor B = C   then   C xor B = A, C xor A = B
        //   Xor(The N encoded character,  K(n)) = ascii N unicode decoded character

        wxString decodedPass;

        int c=0;
        wxChar decoXor = 0;
        wxChar character = 0;

        int len = strPass.Len();
        for (c=0;c<len;c++)
        {
            decoXor=0;          
            character = strPass[c];
            decoXor ^= GetPassCharW(c);           
            decoXor ^= character;

            decodedPass.Append(decoXor);
        }

        switch(formatOutput)
        {
        case STRING:
            *strOutput = decodedPass;            //pass from local-variable to extern-variable
            break;
        case BINARY:            
            binOutput->AppendData(decodedPass,decodedPass.Len() * sizeof(wxChar));   //save decoded pass in extern-memorybyffer
            break;
        }
    }
}

void License::EncodePass(wxString strPass, wxMemoryBuffer &binPass)
{
    workPass(STRING,BINARY,ENCODE,&strPass,NULL,NULL,&binPass);
}

void License::EncodePass(wxString strPass, wxString &binStrPass)
{
    workPass(STRING,STRING,ENCODE,&strPass,NULL,&binStrPass,NULL);
}

wxString License::DecodePass(wxString binStrPass)
{
    wxString decodedPass;
    workPass(STRING,STRING,DECODE,&binStrPass,NULL,&decodedPass,NULL);
    return decodedPass;
}

wxString License::Encode2Validate(const wxString username, const wxString password)
{
    /*
      The algorithm to encode a license for request a validation (and get the expiration date).
      tukero@gmail.com
      -

      * = multiplication

      NOTE: N go from 0 to 7 (expiry server validates 8 characteres only)
      .------------------------------------ ENCODING THE USERNAME & PASSWORD---------------------------------.
      |                                                                                                      |
            N Character of Username    N Character of Password -> C = last 2 BITS of the password
                   |                 /                            |
                   |               /                2*N      2 evelated to C
                   |             /                    \          /
                   |           /                     (multiplication)
                   |         /                           |
                    \      /            .-------------- EF
                     \    /             |          [EF = 2*N * (2 elevated to C)]
                      XOR               |                |
                       |                |                |
                      AB --------------XOR               |
          (AB is the result of          |        F (F are the last 4 bits in the EF number)
          the XOR operation)           GH               /
                       |                |             / 
                       A                '- ->- - -  /  - - - - - ->.
             (A are the first 4 bits             /                 |
              in the AB number)               /                    |
                             \             /                       | 
                                 \      /                          |
                                   \  /                            |
                                    XOR                            H (H are the last 4 bits in the GH number)
                                     =                             =
                         Position of the character       Position of the character 
                            in the second table             in the first table
      |                                                                                                      |
      '------------------------------------------------------------------------------------------------------'

      NOTE: N go from 0 to length of the username - 1
      .------------------------------------ ENCODING THE USERNAME -------------------------------------------.
      |                                                                                                      |
                                            N Character of Username
                                                      |
                                                     JK 
                                            (JK are the N character in hexadecimal,
                                             J = first 4 bits, K = last 4 bits)
                                                      |
                                                    /   \
                                                 /         \
                                              /               \
                                             J                 K       
                                        Position in        Position in
                                        the table 1        the table 2
      |                                                                                                      |
      '------------------------------------------------------------------------------------------------------'

      FINAL STRING ENCODED = ENCODE(USERNAME&PASSWORD) + ENCODE(USERNAME)
                                                       + = concatenation
    */
    int P1, CL, BL, EDX;

    static const wxString table1 = wxT("ZCBMKHFSQETUOXVN");
    static const wxString table2 = wxT("QAPLWSMKCDIJEFBH");
    wxString codificado;

    wxChar charUser, charPass;

    unsigned int c = 0;
    for (c=0 ; c <= 0x7 && c < password.Len(); c++)
    {
        charUser = (c < username.Len() ? username[c] & 0xff : 0);
        charPass = password[c] & 0xff;

        BL = (2 * c) << (charPass & 3);

        P1 = charPass ^ charUser;
        CL = (P1 >> 4) ^ (BL >> 4);
        codificado.Append(table2[CL]);

        EDX = (P1 ^ BL) & 0x0f;
        codificado.Append(table1[EDX]);
    }
   
    for (c=0;c < username.Len();c++)
    {
        charUser = username[c] & 0xff;
        
        codificado.Append(table1[charUser >> 4]);
        codificado.Append(table2[charUser & 0x0f]);
    }
    return codificado;
}